package com.qida.clm.core.utils;

import android.util.Log;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by xiexiang on 2015/10/23.
 * <li>{@link Field}</li>
 * <li>{@link Method}</li>
 */
public class ReflectUtils {

    private static final String TAG = ReflectUtils.class.getSimpleName();

    private ReflectUtils(){}

    public static Field getField(Class<?> clazz,String fieldName){
        Field field = null;
        for (;;){
            try {
                field = clazz.getDeclaredField(fieldName);
                break;
            } catch (NoSuchFieldException e) {
                clazz = clazz.getSuperclass();
                if(clazz == null) break;
            }
        }
        return field;
    }

    public static Method getMethod(Class<?> clazz,String name,Class<?>... parameterTypes){
        Method method = null;
        for(;;){
            try {
                method = clazz.getDeclaredMethod(name, parameterTypes);
                break;
            } catch (NoSuchMethodException e){
                clazz = clazz.getSuperclass();
                if(clazz == null) break;
            }
        }
        return method;
    }

    public static <T> T invokeMethod(Object object,String methodName,Object... objects){
        try {
            Class clazz = objectToClass(object);
            Method method = getMethod(clazz, methodName, objectToClass(objects));
            if(method == null){
                Log.e(TAG,"method not found:"+methodName);
                return null;
            }
            method.setAccessible(true);
            return (T)method.invoke(object,objects);
        } catch (IllegalAccessException e) {
            Log.e(TAG,"access method fail:"+methodName);
            return null;
        } catch (InvocationTargetException e) {
            Log.e(TAG,"invoke method fail:"+methodName);
            return null;
        }
    }

    public static <T> T getFiledValue(Object object,String fieldName){
        try {
            Class clazz = objectToClass(object);
            Field field = getField(clazz, fieldName);
            if(field == null){
                Log.e(TAG,"[getFiledValue] field not found:"+fieldName);
                return null;
            }
            field.setAccessible(true);
            return (T)field.get(object);
        } catch (IllegalAccessException e){
            Log.e(TAG,"access field fail:"+fieldName);
            return null;
        }
    }

    public static boolean setFieldValue(Object object,String fieldName,Object value){
        Class clazz = objectToClass(object);
        Field field = getField(clazz,fieldName);
        if(field != null){
            Log.e(TAG,"[setFieldValue] field not found:"+fieldName);
            return setFieldValue(object,field,value);
        }
        return false;
    }

    private static boolean setFieldValue(Object object,Field field,Object value){
        try {
            field.setAccessible(true);
            field.set(object,value);
            return true;
        } catch (IllegalAccessException e) {
            return false;
        }
    }

    public static Class<?>[] objectToClass(Object... objects){
        int length = objects.length;
        Class<?>[] clazz = new Class[length];
        for (int i=0;i<length;i++){
            clazz[i] = objectToClass(objects[i]);
        }
        return clazz;
    }

    private static Class objectToClass(Object o){
        if(o instanceof Class){
            return (Class)o;
        }
        return o.getClass();
    }
}